package com.csx.governance.traffic.core.interceptor;

import com.csx.governance.traffic.common.CopyObjectReference;
import com.csx.governance.traffic.common.exception.TrafficRequestShouldNotContinueException;
import com.csx.governance.traffic.core.context.TrafficRequest;
import com.csx.governance.traffic.core.context.TrafficResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Comparator;
import java.util.List;

/**
 * 请求处理拦截器执行器，内含一系列排好序的拦截器，能够按序执行
 * @author cuisongxu
 * @date 2023/3/18 11:10
 */
public class TrafficHandlerInterceptorRunner {

    private final Logger logger = LoggerFactory.getLogger(TrafficHandlerInterceptorRunner.class);

    private final List<? extends TrafficAbstractHandlerInterceptor> sortedInterceptors;

    public TrafficHandlerInterceptorRunner(List<? extends TrafficAbstractHandlerInterceptor> interceptors) {
        CopyObjectReference<List<? extends TrafficAbstractHandlerInterceptor>> copyObjectReference = new CopyObjectReference<>(interceptors);
        List<? extends TrafficAbstractHandlerInterceptor> copyInterceptors = copyObjectReference.get();
        copyInterceptors.sort(Comparator.comparing(TrafficAbstractHandlerInterceptor::getOrder));
        this.sortedInterceptors = copyInterceptors;
    }

    public void preHandle(TrafficRequest request, TrafficResponse response) {
        boolean shouldContinue;
        for (TrafficAbstractHandlerInterceptor interceptor : sortedInterceptors) {
            try {
                shouldContinue = interceptor.preHandle(request, response);
                if (!shouldContinue) {
                    throw new TrafficRequestShouldNotContinueException("TrafficRestTemplateInterceptor intercept should not continue");
                }
            }catch (Exception ex) {
                logger.error("interceptor [" + interceptor.getClass().getName() + "] preHandle() failed because {}", ex.getMessage());
                throw ex;
            }
        }
    }

    public void postHandle(TrafficRequest request, TrafficResponse response) {
        sortedInterceptors.forEach(interceptor -> interceptor.postHandle(request, response));
    }

    public void afterCompletion(TrafficRequest request, TrafficResponse response, Throwable ex) {
        sortedInterceptors.forEach(interceptor -> interceptor.afterCompletion(request, response, ex));
    }
}
